package com.fancy.application.sys.rest.service.impl;

import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fancy.application.common.service.impl.BaseService;
import com.fancy.application.common.utils.IPAddressUtil;
import com.fancy.application.common.utils.RedisUtil;
import com.fancy.application.sys.rest.api.TokenParam;
import com.fancy.application.sys.rest.api.TokenResult;
import com.fancy.application.sys.rest.entity.SysRestPolicy;
import com.fancy.application.sys.rest.mapper.SysRestPolicyMapper;
import com.fancy.application.sys.rest.service.ISysRestMainService;
import com.fancy.application.sys.rest.service.ISysRestPolicyService;

import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.List;

/**
* fancyCode 自动生成v1.5
* @author wison
* 2022-08-09
* email：wurong715@163.com
*/
@Log4j2
@Service("sysRestPolicyService")
public class SysRestPolicyServiceImpl extends BaseService<SysRestPolicyMapper,SysRestPolicy> implements ISysRestPolicyService {

    @Resource
    private RedisUtil redisUtil;
    @Resource
    private ISysRestMainService sysRestMainService;

    /**
     * 生成一个有效期的token
     *
     * @param tokenParam
     * @return
     */
    @Override
    public TokenResult generateToken(TokenParam tokenParam) {
        if(StrUtil.isEmpty(tokenParam.getRestId())){
            String msg = "appId为空.";
            log.warn(msg);
            return new TokenResult(msg);
        }
        if(StrUtil.isEmpty(tokenParam.getKey())){
            String msg = "secKey为空.";
            log.warn(msg);
            return new TokenResult(msg);
        }

        return this.generateTokenStr(tokenParam);
    }

    /**
     * 根据客户端的ip地址，来校验绑定ip
     *
     * @param fdPolicyId
     * @param request
     * @return
     */
    @Override
    public boolean checkWhiteList(String fdPolicyId, HttpServletRequest request) {
        SysRestPolicy sysRestPolicy = getPolicyById(fdPolicyId);
        if(sysRestPolicy == null) return false;
        String fdAuthIp = sysRestPolicy.getFdAuthIp();
        String clientIp = IPAddressUtil.getIPAddress(request);
        if(StrUtil.isNotEmpty(fdAuthIp)&&!StrUtil.equals(clientIp,IPAddressUtil.LOCALHOST)){
            List<String> ips = StrUtil.split(fdAuthIp, ";");
            return ips.contains(clientIp);
        }
        return true;
    }

    /**
     * 生成token字符串
     * @param tokenParam
     * @return
     */
    private TokenResult generateTokenStr(TokenParam tokenParam) {
        SysRestPolicy policy = getPolicyByAppKey(tokenParam.getRestId(),tokenParam.getKey());
        if(StrUtil.equals(policy.getFdKey(), tokenParam.getKey())){
            String signature = SecureUtil.md5(tokenParam.toString());
            String tokenRedisKey = getRedisTokenKey(signature);
            long expireTime = policy.getFdAuthTime().longValue();
            if(expireTime==0L){ //不允许为0，默认五分钟
                expireTime = 5L;
            }
            redisUtil.set(tokenRedisKey,signature,expireTime*60);  //设置失效时间
            return new TokenResult(signature,"Token生成成功");
        }else{
            return new TokenResult("密钥校验失败！");
        }

    }

    private String getRedisTokenKey(String signature){
        return "restToken"+signature;
    }

    @Override
    public CheckURIResult checkURI(String fdPolicyId, HttpServletRequest request) {
        SysRestPolicy sysRestPolicy = getPolicyById(fdPolicyId);
        if(sysRestPolicy == null) return new CheckURIResult("未找到安全策略");
        String fdAuthType = sysRestPolicy.getFdAuthType();
        if(EnumUtil.equals(authType.anno,fdAuthType)){  //匿名直接访问
            return new CheckURIResult(Boolean.TRUE,"");
        }else{
            //需要校验token
            String token = request.getHeader("Authorization");
            if(StrUtil.isEmpty(token))return new CheckURIResult("未找到token");
            String redisToken = getRedisTokenKey(token);
            if(redisUtil.hasKey(redisToken)){
                return new CheckURIResult(Boolean.TRUE,"success");
            }else{
                return new CheckURIResult("token已失效");
            }
        }
    }

    private SysRestPolicy getPolicyByAppKey(String restId,String key){
        LambdaQueryWrapper<SysRestPolicy> policyLambdaQueryWrapper = new LambdaQueryWrapper<>();
        policyLambdaQueryWrapper.eq(SysRestPolicy::getFdKey,key).eq(SysRestPolicy::getFdRestId,restId);
        return this.getOne(policyLambdaQueryWrapper);
    }

    private SysRestPolicy getPolicyById(String fdPolicyId) {
        List<SysRestPolicy> sysRestPolicyList = getSysRestPolicys();
        for(SysRestPolicy policy:sysRestPolicyList){
            if(StrUtil.equals(policy.getFdId(), fdPolicyId)){
                return policy;
            }
        }
        return null;
    }

    @Override
    public boolean saveOrUpdate(SysRestPolicy sysRestPolicy) {
        //更新redis缓存
        boolean resultFlag = super.saveOrUpdate(sysRestPolicy);
        sysRestMainService.updateCache();
        return resultFlag;
    }

    private List<SysRestPolicy> getSysRestPolicys(){
        return (List<SysRestPolicy>) redisUtil.get(this.redisKey);
    }
}
